package plgdb

import (
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/utils"
	"fmt"
	"net/http"
	"strings"
	"time"
)

func (this *PlgDBBase) CheckRegisterDBHandler(urisuffix, resid, urltype string, prohandle func(req *PlgDBRequest) bool) {
	this.CheckRegisterApiURI(urisuffix, func(w http.ResponseWriter, r *http.Request) {
		req := this.NewPlgDBRequest(w, r)
		req.Req.SetKeyValue("__resid", resid)
		if this.OnBeforeRequestFunc != nil {
			this.OnBeforeRequestFunc(req)
		}
		if prohandle(req) {
			this.InnerDBHandler(urltype, req)
		}
	})
}

func (this *PlgDBBase) NewPlgDBRequest(w http.ResponseWriter, r *http.Request) *PlgDBRequest {
	req := NewPlgDBRequest(w, r)
	if this.Http_allow_cross_access {
		PrjHttpUtils.AllowCrossAccessSet(w)
	}
	req.DecodeRequestBodyAsJSON()

	req.OnBeforeResponseFunc = func(sender *PrjHttpUtils.HttpRec) bool {
		if req.OnDBBeforeResponseFunc != nil {
			return req.OnDBBeforeResponseFunc(req)
		}
		return true
	}

	if this.TraceDebug == 1 {
		var sb utils.BytesBuilder
		sb.Appendf("[%s]请求参数\n", req.ClientAddr())
		sb.Appendf("url:%s\n", req.ReqR.URL.String())
		sb.Appendf("Method:%s\n", req.ReqR.Method)
		PrjHttpUtils.GetRequestHeader(req.ReqR.Header, ":", "\n", &sb)
		sb.Appendf("\n")
		sb.Write(req.BodyBuf)
		sb.Appendf("\n")
		t1 := time.Now()
		req.OnResponseFunc = func(respHeader http.Header, body []byte) {
			sb.Appendf("响应(%d ms)\n", time.Since(t1).Milliseconds())
			PrjHttpUtils.GetRequestHeader(respHeader, ":", "\n", &sb)
			sb.Appendf("\n")
			sb.Write(body)
			sb.Appendf("\n")
			this.PushWarnlist("%s", sb.String())
		}
	}

	return req
}

func (this *PlgDBBase) InnerHttpDBQueue(req *PlgDBRequest, fn func()) {
	wt := utils.NewWaitWithTimeoutAdd1()
	utils.DefaultWorkers().PostTaskFunc(this.Dbup_task_key, func() {
		fn()
		wt.Done()
	})
	if !wt.WaitFor(time.Second * 30) {
		req.ResponseJSONValues("code", -1, "errcode", 503, "msg", fmt.Sprintf("[%s]数据库队列操作超时", this.Dbup_task_key))
	}
}

func (this *PlgDBBase) InnerDBHandler(urltype string, req *PlgDBRequest) {
	if utils.GoFunCatchException {
		str := req.Req.AsJSONStringEx(false, false)
		defer utils.PanicHandlerWithDebugString(fmt.Sprintf("%s\r\n%s", urltype, str))
	}
	var errcode int
	var err error
	if len(urltype) <= 1 || strings.HasPrefix(urltype, "/list") {
		errcode, err = this.OnHttpRequestList(req)
	} else if strings.HasPrefix(urltype, "/get") {
		req.Req.SetKeyValue("__single", "data")
		errcode, err = this.OnHttpRequestList(req)
	} else {
		if len(this.Dbup_task_key) > 0 {
			wt := utils.NewWaitWithTimeoutAdd1()
			utils.DefaultWorkers().PostTaskFunc(this.Dbup_task_key, func() {
				if strings.HasPrefix(urltype, "/update") {
					errcode, err = this.OnHttpDBResUpdateOne(req)
				} else if strings.HasPrefix(urltype, "/exupdate") {
					errcode, err = this.OnHttpDBResExUpdateOne(req)
				} else if strings.HasPrefix(urltype, "/batchupdate") {
					errcode, err = this.OnHttpDBResBatchUpdate(req)
				} else if strings.HasPrefix(urltype, "/add") {
					errcode, err = this.OnHttpDBResInsertOne(req)
				} else if strings.HasPrefix(urltype, "/del") {
					errcode, err = this.OnHttpDBResDelOne(req)
				} else if strings.HasPrefix(urltype, "/exec") {
					errcode, err = this.OnHttpDBResExec(req)
				}
				wt.Done()
			})
			if !wt.WaitFor(time.Second * 30) {
				errcode = 503
				err = fmt.Errorf("[%s]数据库队列操作超时", this.Dbup_task_key)
			}
		} else {
			if strings.HasPrefix(urltype, "/update") {
				errcode, err = this.OnHttpDBResUpdateOne(req)
			} else if strings.HasPrefix(urltype, "/exupdate") {
				errcode, err = this.OnHttpDBResExUpdateOne(req)
			} else if strings.HasPrefix(urltype, "/batchupdate") {
				errcode, err = this.OnHttpDBResBatchUpdate(req)
			} else if strings.HasPrefix(urltype, "/add") {
				errcode, err = this.OnHttpDBResInsertOne(req)
			} else if strings.HasPrefix(urltype, "/del") {
				errcode, err = this.OnHttpDBResDelOne(req)
			} else if strings.HasPrefix(urltype, "/exec") {
				errcode, err = this.OnHttpDBResExec(req)
			}
		}
	}

	if req.TracesqlBuilder.Len() > 0 {
		req.SetValues("tracesql", req.TracesqlBuilder.String())
	}

	if errcode != 0 && err != nil {
		req.SetValues("code", -1, "errcode", errcode, "msg", err.Error())
		req.CheckResponseAsJson()
	} else if err != nil {
		req.SetValues("code", -1, "msg", err.Error())
		req.CheckResponseAsJson()
	} else {
		req.SetValues("code", 0)
		req.CheckResponseAsJson()
	}
	return
}

func (this *PlgDBBase) OnHttpDBHandler(w http.ResponseWriter, r *http.Request) {
	if utils.GoFunCatchException {
		defer utils.PanicHandlerWithDebugString(fmt.Sprintf("%s-%s-OnHttpDBHandler", this.PlugId))
	}

	req := this.NewPlgDBRequest(w, r)

	if req.ReqR.Method == "OPTIONS" {
		PrjHttpUtils.ResponseJSONValues(w, "code", 0)
		return
	}

	remainUrl := strings.TrimPrefix(r.URL.Path, this.api_dbhandler)
	this.InnerDBHandlerEx(remainUrl, req)
	//remainUrl = strings.TrimPrefix(remainUrl, "/")
	//resId, remainUrl := utils.CutPrefixByRune(remainUrl, 0, 0, '/')
	//if len(resId) == 0 {
	//	req.SetValues("code", -1, "errcode", ERR_IN_PARAM_INVALID, "msg", "请指定资源ID")
	//	req.ResponseAsJSON()
	//	return
	//}
	//
	////  req.CheckDecodeBody()
	//req.Req.SetKeyValue("__resid", resId)
	//if req.QryAsString("__datasource", "") == "" && len(this.Default_datasourceid) > 0 {
	//	req.Req.SetKeyValue("__datasource", this.Default_datasourceid)
	//}
	//
	//if this.OnBeforeRequestFunc != nil {
	//	this.OnBeforeRequestFunc(req)
	//}
	//
	//urltype := remainUrl
	//
	//this.InnerDBHandler(urltype, req)
}

func (this *PlgDBBase) InnerDBHandlerEx(dbsuffixuri string, req *PlgDBRequest) {
	if utils.GoFunCatchException {
		defer utils.PanicHandlerWithDebugString(fmt.Sprintf("%s-%s-OnHttpDBHandler", this.PlugId))
	}

	remainUrl := strings.TrimPrefix(dbsuffixuri, "/")
	resId, remainUrl := utils.CutPrefixByRune(remainUrl, 0, 0, '/')
	if len(resId) == 0 {
		req.SetValues("code", -1, "errcode", ERR_IN_PARAM_INVALID, "msg", "请指定资源ID")
		req.ResponseAsJSON()
		return
	}

	//  req.CheckDecodeBody()
	req.Req.SetKeyValue("__resid", resId)
	if req.QryAsString("__datasource", "") == "" && len(this.Default_datasourceid) > 0 {
		req.Req.SetKeyValue("__datasource", this.Default_datasourceid)
	}

	if this.OnBeforeRequestFunc != nil {
		this.OnBeforeRequestFunc(req)
	}

	urltype := remainUrl

	this.InnerDBHandler(urltype, req)
}

/*
**

	重载资源
*/
func (this *PlgDBBase) OnHttpResReloadHandler(w http.ResponseWriter, r *http.Request) {
	n, err := this.reloadFromUrl()
	if err != nil {
		PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", err.Error())
	} else {
		PrjHttpUtils.ResponseJSONValues(w, "code", 0, "n", n)
	}
}

/*
*

	{
	   "__datasource":"main",
	   "__dbname":"dbname",     // 指定数据库名(数据库配置参数中如果没有$dbname$, 如果main指定不可以替换, 则该参数无效)
	   "__resid":"xxxx",        // 对应的配置id, 提取配置中的$sel
	   "__single":"data",       // 只取一条
	   "page":1,                // 获取第几页数据 从1:开始
	   "pagesize":20,           // 每页20条
	   "reqtotal":0,            // 是否获取总记录数,  默认为:1(获取), 0不获取 , 配置中$sel $field$配置, 或者配置"countsql"
	   "orderby":" id desc",    // 字段排序, 如果传入该值, 会覆盖掉配置中的"orderby" 配置
	   "args":{
	       "id":"001"           // id对应参数为配置中的args参数
	    }
	}
*/
func (this *PlgDBBase) OnHttpRequestList(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)

	// 提取url的参数
	args := req.Req.ForceByPath("args")
	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "args" {
			args.SetKeyString(strs[1], v)
		}
		return true
	})

	singlekeyname := req.QryAsStringEx("__single", "", true)
	if len(singlekeyname) > 0 {
		if utils.StrIndexIgnoreCase(singlekeyname, "true", "1", "是") != -1 {
			singlekeyname = "data"
		}
	}

	qryParam := NewDBQryParma()
	qryParam.DataSourceid = datasourceid
	qryParam.DBName = dbname
	qryParam.ResID = resid
	qryParam.Req = req.Req
	qryParam.Resp = req.Resp
	qryParam.Args = args
	qryParam.SingleName = singlekeyname
	qryParam.HttpReq = req
	defer qryParam.Close()
	return this.DBResQryList(qryParam)
}

func (this *PlgDBBase) OnHttpDBResUpdateOne(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)
	if len(resid) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("请指定资源ID(resid)[%s]", resid)
	}

	upData := req.GetUpData()

	param := NewDBUpdateParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Data = upData
	param.HttpReq = req
	defer param.Close()

	return this.DBResUpdateOne(param)
}

func (this *PlgDBBase) OnHttpDBResExUpdateOne(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)
	if len(resid) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("请指定资源ID(resid)[%s]", resid)
	}

	// 提取url的参数
	upData := req.Req.ValueByName("data")
	if upData == nil {
		upData = req.Req
	}
	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "data" {
			upData.SetKeyString(strs[1], v)
		}
		return true
	})

	param := NewDBUpdateParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Data = upData
	param.HttpReq = req
	defer param.Close()

	return this.DBResExUpdateOne(param)
}

func (this *PlgDBBase) OnHttpDBResInsertOne(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)

	// 提取url的参数
	upData := req.Req.ValueByName("data")
	if upData == nil {
		upData = req.Req
	}
	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "data" {
			upData.SetKeyString(strs[1], v)
		}
		return true
	})

	param := NewDBUpdateParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Data = upData
	param.HttpReq = req
	defer param.Close()

	return this.DBResInsertOne(param)
}

func (this *PlgDBBase) OnHttpDBResDelOne(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)
	if len(resid) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("请指定资源ID(resid)[%s]", resid)
	}

	// 提取url的参数
	upData := req.Req.ValueByName("data")
	if upData == nil {
		upData = req.Req
	}

	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "data" {
			upData.SetKeyString(strs[1], v)
		}
		return true
	})

	param := NewDBUpdateParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Data = upData
	param.HttpReq = req
	defer param.Close()
	return this.DBResDelOne(param)
}

func (this *PlgDBBase) OnHttpDBResBatchUpdate(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)
	if len(resid) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("请指定资源ID(resid)[%s]", resid)
	}

	// 提取url的参数
	upData := req.Req.ValueByName("data")
	if upData == nil {
		upData = req.Req
	}

	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "data" {
			upData.SetKeyString(strs[1], v)
		}
		return true
	})

	param := NewDBUpdateParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Data = upData
	param.HttpReq = req
	defer param.Close()

	return this.DBResBatchUpdate(param)
}

func (this *PlgDBBase) OnHttpDBResExec(req *PlgDBRequest) (errcode int, err error) {
	datasourceid := req.QryAsStringEx("__datasource", "", true)
	dbname := req.QryAsStringEx("__dbname", "", true)

	resid := req.QryAsStringEx("__resid", "", true)
	if len(resid) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("请指定资源ID(resid)[%s]", resid)
	}

	args := req.Req.ValueByName("args")
	if args == nil {
		args = req.Req
	}
	req.RangeURLParam(func(k, v string) bool {
		strs := strings.SplitN(k, ".", 2)
		if len(strs) == 2 && strs[0] == "args" {
			args.SetKeyString(strs[1], v)
		}
		return true
	})

	param := NewDBExecParma()
	param.DataSourceid = datasourceid
	param.DBName = dbname
	param.ResID = resid
	param.Req = req.Req
	param.Resp = req.Resp
	param.Args = args
	param.HttpReq = req
	defer param.Close()

	return this.DBResExec(param)
}
